package com.iris.live.services.services.impl;

import com.google.common.base.Strings;
import com.iris.live.services.common.DateFormatUtils;
import com.iris.live.services.common.JsonObjectUtils;
import com.iris.live.services.common.StringUtils;
import com.iris.live.services.common.reconsitution.ApprovalWorkFlowEnum;
import com.iris.live.services.common.reconsitution.FinanceConstant;
import com.iris.live.services.data.models.*;
import com.iris.live.services.data.repositories.*;
import com.iris.live.services.models.PageData;
import com.iris.live.services.models.ResultData;
import com.iris.live.services.report.ExcelReportContext;
import com.iris.live.services.report.IExcelReportService;
import com.iris.live.services.report.sources.ExportMoneyHistorySource;
import com.iris.live.services.requestbody.FinanceReceivablesBody;
import com.iris.live.services.services.FinanceReceivablesService;
import com.iris.live.services.services.SetService;
import com.iris.live.services.vo.finance.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import javax.annotation.Resource;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import static com.iris.live.services.common.DateFormatUtils.TIME_FORMAT_STR_YYYY_MM_DD;

/**
 * 财务系统对接模块(新车收款模块)--业务层
 */
@Service
@Transactional
public class FinanceReceivablesServiceImpl implements FinanceReceivablesService{
    private static final Logger logger = LoggerFactory.getLogger(FinanceReceivablesServiceImpl.class);

    private AtomicInteger billNo = new AtomicInteger(0);

    @Resource
    private FinanceReceivablesRepository financeReceivablesRepository;

    @Resource
    private 销售财务表Repository financialRepository;

    @Resource
    private 销售财务账目表Repository financialDetailRepository;

    @Resource
    private 销售财务账目单号Repository 销售财务账目单号Repository;

    @Resource
    private 数据字典Repository 数据字典Repository;

    @Resource
    private IExcelReportService excelReportService;

    @Resource
    private ExportMoneyHistorySource exportMoneyHistorySource;

    @Resource
    private 报价订单表Repository 报价订单表Repository;

    @Resource
    private 报价单表Repository 报价单表Repository;

    @Resource
    private 报价交车表Repository 报价交车表Repository;

    @Resource
    private SetService setService;

    @Resource
    private Lsh库存表Repository lsh库存表Repository;

    @Resource
    private PushApprovalWorkFlowRepository2 pushApprovalWorkFlowRepository2;

    @Override
    public ResultData updateFinanceOrderTotalAmount(String quotedNum, Double amount) {
        financialRepository.updateOrderTotalAmount(quotedNum,amount);
        return new ResultData("true",null);
    }

    @Override
    public ResultData updateFinanceInvoiceStatus(String quotedNum, String status) {
        financialRepository.updateInvoiceStatus(quotedNum,status);
        return new ResultData("true",null);
    }

    @Override
    public ResultData updateFinanceReceivablesStatus(String quotedNum, String status) {
        financialRepository.updateReceivablesStatus(quotedNum,status);
        return new ResultData("true",null);
    }

    @Override
    @Transactional(readOnly = true)
    public ResultData getOrderDetail(String quotedNum) {
        ResultData result = new ResultData();
        List list =financeReceivablesRepository.getOrderDetail(quotedNum);
        if (list != null && !list.isEmpty()) {
            result.setPageData(new PageData(list,list.size()));
        }
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public ResultData getMoneyHistory(String quotedNum,Integer pageSize,Integer pageIndex) {
        ResultData result = new ResultData();
        PageData pageData = financeReceivablesRepository.getMoneyHistory(quotedNum,pageSize,pageIndex);
        result.setPageData(pageData);
        return result;
    }

    @Override
    public void exportMoneyHistory(String quotedNum, Integer pageSize, Integer pageIndex, OutputStream outputStream) {
        try {
            Map param = new HashMap();
            param.put("quotedNum",quotedNum);
            param.put("pageSize",pageSize);
            param.put("pageIndex",pageIndex);
            ExcelReportContext context = new ExcelReportContext();
            context.setTemplate("templates/财务款项历史导出模板.xlsx")
                    .setFileName("财务款项历史导出模板.xlsx")
                    .setSource(exportMoneyHistorySource)
                    .setStaticSheet(true)
                    .addParam("param", param);

            excelReportService.export(context, outputStream);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("导出列表数据异常", e);
        }
    }

    @Override
    public ResultData receivables(ReceivablesAndRefundRequest params) {
        ResultData result = new ResultData();
        // 校验金额
        if (!StringUtils.isPositiveNumber(params.money)) {
            result.setMessage("金额必须为正数");
            result.setResult("false");
            return result;
        }

        Timestamp time = new Timestamp(System.currentTimeMillis());  // 当前时间
        销售财务表Model financialModel = null;
        BigDecimal money = new BigDecimal(params.money).setScale(2,BigDecimal.ROUND_HALF_UP); // 金额
        // 获得最新的报价单数据
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(params.initNum);
        // 获得单子的订单总价
        BigDecimal totalPrice = financeReceivablesRepository.getOrderTotalPrice(quotedModel.get报价编号().toString());

        financialModel = financialRepository.findByOrderNumber(params.initNum);
        if (financialModel != null) {  // 已经有财务主数据,更新金额
            // 若是退订，则不可以收款
            if (isRetreatStatus(params.initNum)) {
                result.setMessage("已退订，不可再收款！");
                result.setResult("false");
                return result;
            }

            financialModel.set收款金额(financialModel.get收款金额().add(money));
            financialModel.set订单总价(totalPrice);
            financialModel.set修改时间(time);
            financialModel.set修改用户(params.user);
        } else {  // 没有财务主数据,创建数据
            financialModel = new 销售财务表Model();
            financialModel.set许可(params.permit);
            financialModel.set订单编号(params.initNum);
            financialModel.set订单总价(totalPrice);
            financialModel.set收款金额(money);
            financialModel.set退款金额(new BigDecimal(0.00));
            financialModel.set挂账金额(new BigDecimal(0.00));
            financialModel.set核销金额(new BigDecimal(0.00));
            financialModel.set开票金额(new BigDecimal(0.00));
            financialModel.set退票金额(new BigDecimal(0.00));
            financialModel.set红冲收款金额(new BigDecimal(0.00));
            financialModel.set红冲退款金额(new BigDecimal(0.00));
            financialModel.set红冲挂账金额(new BigDecimal(0.00));
            financialModel.set红冲核销金额(new BigDecimal(0.00));
            financialModel.set创建用户(params.user);
            financialModel.set创建时间(time);
            financialModel.set修改时间(time);
            financialModel.set修改用户(params.user);
            financialModel.set删除状态("0");
        }
        financialRepository.save(financialModel);

        // 插入账目明细
        销售财务账目表Model financialDetailModel = new 销售财务账目表Model();
        financialDetailModel.set财务编号(financialModel.get财务编号());
        financialDetailModel.set订单编号(params.initNum);
        financialDetailModel.set账目日期(new Date(DateFormatUtils.getFormatDate(params.billDate, TIME_FORMAT_STR_YYYY_MM_DD).getTime()));
        financialDetailModel.set账目类型(FinanceConstant.SHOUKUAN);
        financialDetailModel.set支付方式(params.payMethod);
        financialDetailModel.set账目单号(generateOperationNumber(FinanceConstant.S));
        financialDetailModel.set账目金额(money);
        financialDetailModel.set交易凭证号(params.tradeNO);
        financialDetailModel.set是否红冲("0");
        financialDetailModel.set备注(params.remarks);
        financialDetailModel.set创建用户(params.user);
        financialDetailModel.set创建时间(time);
        financialDetailModel.set修改时间(time);
        financialDetailModel.set修改用户(params.user);
        financialDetailModel.set删除状态("0");
        financialDetailModel.set操作日期(time);
        financialDetailRepository.save(financialDetailModel);
        return result;
    }

    @Override
    public ResultData refund(ReceivablesAndRefundRequest params) {
        ResultData result = new ResultData();
        // 校验金额
        if (!StringUtils.isPositiveNumber(params.money)) {
            result.setMessage("金额必须为正数");
            result.setResult("false");
            return result;
        }

        Timestamp time = new Timestamp(System.currentTimeMillis());  // 当前时间
        BigDecimal money = new BigDecimal(params.money).setScale(2,BigDecimal.ROUND_HALF_UP); // 金额
        // 获得最新的报价单数据
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(params.initNum);
        // 获得单子的订单总价
        BigDecimal totalPrice = financeReceivablesRepository.getOrderTotalPrice(quotedModel.get报价编号().toString());
        // 获取当前单子的财务信息
        销售财务表Model financialModel = financialRepository.findByOrderNumber(params.initNum);

        // 没有先收款，不可以退款
        if (financialModel == null) {
            result.setMessage("请先进行收款操作，再退款！");
            result.setResult("false");
            return result;
        }

        BigDecimal actualReceivablesMoney = financialModel.get收款金额().add(financialModel.get红冲收款金额()); // 实际收款金额
        BigDecimal actualRefundMoney = financialModel.get退款金额().add(financialModel.get红冲退款金额()); // 实际退款金额
        BigDecimal canRefundMoney = actualReceivablesMoney.subtract(actualRefundMoney);  // 可退款金额 = 实收金额 = 收款 - 退款


        if (StringUtils.isNullOrBlank(params.refundReason)) {
            result.setMessage("请选择 退款原因！");
            result.setResult("false");
            return result;
        }
        if ("退订单".equals(params.refundReason) || "修改意向单".equals(params.refundReason) || "修改订单".equals(params.refundReason) || "修改合同".equals(params.refundReason)) {
            // 得到最新的审批记录
            PushApprovalWorkFlowModel approvalModel = pushApprovalWorkFlowRepository2.getTheLastOneByInitNum(params.initNum);
            if (null == approvalModel) {
                result.setMessage("缺少相关审批记录，退款失败！");
                result.setResult("false");
                return result;
            }
            // 退款金额 > 目前可退款金额时(实收金额)，不可以退款
            if (money.compareTo(canRefundMoney) > 0) {
                result.setMessage("本次的退款金额大于实收金额，退款不生效。");
                result.setResult("false");
                return result;
            }
            List<String> statusList = new ArrayList<>();
            statusList.add("1"); // 审批通过
            statusList.add("3");  // 审批自动通过
            Integer approvalType = approvalModel.getType();
            String approvalStatus = approvalModel.getApprovalStatus();

            switch(params.refundReason) {
                case "退订单" :
                    if ((ApprovalWorkFlowEnum.ORDER_RETREAT != approvalType && ApprovalWorkFlowEnum.ORDER_INTENTION_RETREAT != approvalType) ||
                            ((ApprovalWorkFlowEnum.ORDER_RETREAT == approvalType || ApprovalWorkFlowEnum.ORDER_INTENTION_RETREAT == approvalType) && !statusList.contains(approvalStatus))) {
                        result.setMessage("退订未审批通过，退款不生效。");
                        result.setResult("false");
                        return result;
                    }
                    break;
                case "修改意向单" :
                    if (ApprovalWorkFlowEnum.ORDER_INTENTION_UPDATE != approvalType || (ApprovalWorkFlowEnum.ORDER_INTENTION_UPDATE == approvalType && !statusList.contains(approvalStatus))) {
                        result.setMessage("意向单修改未审批通过，退款不生效。");
                        result.setResult("false");
                        return result;
                    }
                    break;
                case "修改订单" :
                    if (ApprovalWorkFlowEnum.ORDER_UPDATE != approvalType || (ApprovalWorkFlowEnum.ORDER_UPDATE == approvalType && !statusList.contains(approvalStatus))) {
                        result.setMessage("订单修改未审批通过，退款不生效。");
                        result.setResult("false");
                        return result;
                    }
                    break;
                case "修改合同" :
                    if (ApprovalWorkFlowEnum.AGREEMENT_UPDATE != approvalType || (ApprovalWorkFlowEnum.AGREEMENT_UPDATE == approvalType && !statusList.contains(approvalStatus))) {
                        result.setMessage("合同修改未审批通过，退款不生效。");
                        result.setResult("false");
                        return result;
                    }
                    break;
            }
        } else { // 多收款的情况
            // 收款未完成
            if (financialModel.get收款状态() == null || FinanceConstant.RECEIVABLES_NOT_COMPLETE.equals(financialModel.get收款状态())) {
                // 退款金额 > 目前可退款金额时(实收金额)，不可以退款
                if (money.compareTo(canRefundMoney) > 0) {
                    result.setMessage("本次的退款金额大于实收金额，退款不生效。");
                    result.setResult("false");
                    return result;
                }
            } else { // 收款完成
                // 退款金额 > （实收金额 - 订单总价）,则不可以退款
                if (money.compareTo(canRefundMoney.subtract(totalPrice)) > 0) {
                    result.setMessage("退款后实收金额低于订单总价，退款不生效。");
                    result.setResult("false");
                    return result;
                }
            }
        }

        // 更新财务主表的金额
        financialModel.set退款金额(financialModel.get退款金额().add(money));
        financialModel.set修改时间(time);
        financialModel.set修改用户(params.user);
        financialRepository.save(financialModel);
        // 插入账目明细
        销售财务账目表Model financialDetailModel = new 销售财务账目表Model();
        financialDetailModel.set财务编号(financialModel.get财务编号());
        financialDetailModel.set订单编号(params.initNum);
        financialDetailModel.set账目日期(new Date(DateFormatUtils.getFormatDate(params.billDate, TIME_FORMAT_STR_YYYY_MM_DD).getTime()));
        financialDetailModel.set账目类型(FinanceConstant.TUIKUAN);
        financialDetailModel.set退款方式(params.payMethod);
        financialDetailModel.set退款原因(params.refundReason);
        financialDetailModel.set账目单号(generateOperationNumber(FinanceConstant.T));
        financialDetailModel.set账目金额(money);
        financialDetailModel.set交易凭证号(params.tradeNO);
        financialDetailModel.set是否红冲("0");
        financialDetailModel.set备注(params.remarks);
        financialDetailModel.set创建用户(params.user);
        financialDetailModel.set创建时间(time);
        financialDetailModel.set修改时间(time);
        financialDetailModel.set修改用户(params.user);
        financialDetailModel.set删除状态("0");
        financialDetailModel.set操作日期(time);
        financialDetailRepository.save(financialDetailModel);
        return result;
    }


    @Override
    @Transactional(readOnly = true)
    public PageData getHangAccountOrder(String quotedNum) {
        List list = financeReceivablesRepository.getOrderDetail(quotedNum);
        PageData page = new PageData(list,list.size());
        return page;
    }

    @Override
    public ResultData saveHangAccount(ReceivablesAndRefundRequest params) {
        ResultData result = new ResultData("false",null,null);
        // 校验金额
        if (!StringUtils.isPositiveNumber(params.money)) {
            result.setMessage("金额必须为正数");
            result.setResult("false");
            return result;
        }

        Timestamp time = new Timestamp(System.currentTimeMillis());  // 当前时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Timestamp ts = DateFormatUtils.getFormatTimestamp("yyyy-MM-dd HH:mm:ss", new java.util.Date());
        销售财务表Model financialModel = null;

        //做出判空处理
        if (Strings.isNullOrEmpty(params.money)){
            result.setResult("false");
            result.setMessage("请输入挂账金额");
            return result;
        }
        if (Strings.isNullOrEmpty(params.billDate)){
            result.setResult("false");
            result.setMessage("请选择挂账日期");
            return result;
        }
        if (Strings.isNullOrEmpty(params.payMethod)){
            result.setResult("false");
            result.setMessage("请选择挂账类别");
            return result;
        }

        BigDecimal money = new BigDecimal(params.money); // 金额
        // 获得最新的报价单数据
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(params.initNum);
        // 获得单子的订单总价
        BigDecimal totalPrice = financeReceivablesRepository.getOrderTotalPrice(quotedModel.get报价编号().toString());
        financialModel = financialRepository.findByOrderNumber(params.initNum);
        if (financialModel != null) {  // 已经有财务主数据,更新金额
            // 若是退订，则不可以挂账
            if (isRetreatStatus(params.initNum)) {
                result.setMessage("已退订，不可再挂账！");
                result.setResult("false");
                return result;
            }

            financialModel.set挂账金额(financialModel.get挂账金额().add(money));
            financialModel.set订单总价(totalPrice);
            financialModel.set修改时间(time);
            financialModel.set修改用户(params.user);
        } else {  // 没有财务主数据,创建数据

            financialModel = new 销售财务表Model();
            financialModel.set许可(params.permit);
            financialModel.set订单编号(params.initNum);
            financialModel.set订单总价(totalPrice);
            financialModel.set挂账金额(money);

            //表设计参数不为空， 参数需要初始化
            financialModel.set退款金额(new BigDecimal(0));
            financialModel.set收款金额(new BigDecimal(0));
            financialModel.set核销金额(new BigDecimal(0));
            financialModel.set开票金额(new BigDecimal(0));
            financialModel.set退票金额(new BigDecimal(0));
            financialModel.set红冲收款金额(new BigDecimal(0));
            financialModel.set红冲退款金额(new BigDecimal(0));
            financialModel.set红冲挂账金额(new BigDecimal(0));
            financialModel.set红冲核销金额(new BigDecimal(0));
            financialModel.set退票金额(new BigDecimal(0));
            financialModel.set退票金额(new BigDecimal(0));

            financialModel.set创建用户(params.user);
            financialModel.set创建时间(time);
            financialModel.set修改用户(params.user);
            financialModel.set修改时间(time);
            financialModel.set删除状态("0");
        }

        financialRepository.save(financialModel);

        // 插入账目明细
        销售财务账目表Model financialDetailModel = new 销售财务账目表Model();
        financialDetailModel.set关联编号(0);
        financialDetailModel.set财务编号(financialModel.get财务编号());

        financialDetailModel.set订单编号(params.initNum);
        financialDetailModel.set账目日期(java.sql.Date.valueOf(params.billDate));
        financialDetailModel.set账目类型("挂账");
        financialDetailModel.set挂账类别(params.payMethod);
        financialDetailModel.set账目金额(money);
        financialDetailModel.set交易凭证号(params.tradeNO);
        financialDetailModel.set是否红冲("0");
        financialDetailModel.set备注(params.remarks);
        financialDetailModel.set创建用户(params.user);
        financialDetailModel.set创建时间(time);
        financialDetailModel.set修改用户(params.user);
        financialDetailModel.set修改时间(ts);
        financialDetailModel.set删除状态("0");
        financialDetailModel.set账目单号(generateOperationNumber(FinanceConstant.G));
        financialDetailModel.set操作日期(time);

        financialDetailRepository.save(financialDetailModel);

        result.setResult("true");
        // 返回给前端财务编号
        result.setMessage(financialModel.get财务编号().toString());
        return result;

    }

    /**
     * 生成操作单据号
     * @param type
     * @return
     */
    @Override
    public String generateOperationNumber(String type){
        int times = 0;
        while(times < 3) {
            try {
                return generateBillNumber(type);
            } catch (Exception exc) {
                times += 1;
                logger.warn("单据号已经被使用，重新生成。");
            }
        }

        return null;
    }

    /**
     * 生成操作单据号
     * @param type
     * @return
     */
    private String generateBillNumber(String type) {
        String date = LocalDate.now().toString().replace("-", "");
        销售财务账目单号Model 单号Model = 销售财务账目单号Repository.selectByType(type);
        if (单号Model == null) {
            // 不存在，则初始化数据
            单号Model = new 销售财务账目单号Model();
            单号Model.set单号类型(type);
            单号Model.set值(date + "_" + "000001");
        } else { // 存在
            String value = 单号Model.get值();
            String dateStr = value.split("_")[0];
            String numberStr = value.split("_")[1];
            // 是否为当天的单号
            if (date.equals(dateStr)) {
                // 仍然是当天的单号 ，单号+1
                int length = ((Integer.valueOf(numberStr) + 1) + "").length();
                String temp = "";
                if (length < 6) {
                    for (int i = 0; i < 6 - length; i++) {
                        temp += "0";
                    }
                }
                单号Model.set值(date + "_" + temp + (Integer.valueOf(numberStr) + 1));
            } else { // 不是当天的单号，产生新一天的数据
                单号Model.set值(date + "_" + "000001");
            }
        }
        销售财务账目单号Repository.save(单号Model);

        // 返回操作单号
        return type + 单号Model.get值().split("_")[0] + 单号Model.get值().split("_")[1];
    }

    @Override
    public PageData getHangAccountDetail(String FinId,Integer pageSize,Integer pageIndex) {
        PageData page = financeReceivablesRepository.getHangAccountDetail(FinId,pageSize,pageIndex);
        return page;
    }

    @Override
    public List getDataDictionaryByTypeCode(String typeCode) {
        return 数据字典Repository.get数据字典表Models(typeCode);
    }

    @Override
    @Transactional(readOnly = true)
    public ResultData getInvoiceDetail(String quotedNum, Integer pageSize, Integer pageIndex) {
        ResultData result = new ResultData();
        result.setPageData(financeReceivablesRepository.getInvoiceDetail(quotedNum,pageSize,pageIndex));
        return result;
    }

    @Override
    public ResultData invoiceRegister(InvoiceRequest params) {
        ResultData result = new ResultData();
        // 校验金额
        if (!StringUtils.isPositiveNumber(params.invoiceMoney)) {
            result.setMessage("金额必须为正数");
            result.setResult("false");
            return result;
        }

        销售财务表Model financialModel = financialRepository.findByOrderNumber(params.initNum);
        if (null == financialModel) {
            result.setMessage("发票登记失败，请先收款！");
            result.setResult("false");
            return result;
        }
        // 逻辑校验
        // 1：如果发票类型是机动车专用发票，开票项目必须是整车票
        数据字典表Model invoiceItemDic = 数据字典Repository.get数据字典By名称(params.invoiceItem);
        数据字典表Model invoiceTypeDic = 数据字典Repository.get数据字典By名称(params.invoiceType);
        if ("type_carSpecial_17".equalsIgnoreCase(invoiceTypeDic.get字典值()) && !"item_allCar".equalsIgnoreCase(invoiceItemDic.get字典值())) {
            result.setMessage("发票类型必须是整车才可以登记机动车专用发票！");
            result.setResult("false");
            return result;
        }

        //没有报价编号
        if (Strings.isNullOrEmpty(params.quotedNum)){
            return new ResultData("false","发票登记失败，没有相关财务数据！");
        }

        报价单表Model quoteModel = 报价单表Repository.findTheLastForFinance((params.initNum));
        if (null == quoteModel) {
            return new ResultData("false","发票登记失败，没有相关财务数据！");
        }

        报价订单表Model orderModel  = 报价订单表Repository.findOrderById(quoteModel.get订单编号());
        if (null == orderModel) {
            return new ResultData("false","发票登记失败，没有相关财务数据！");
        }

        // 开整车票 ： （1）收款状态为已完成  （2） 销售顾问提交开票请求（开票O）
        if ("item_allCar".equalsIgnoreCase(invoiceItemDic.get字典值())){
            if (!FinanceConstant.RECEIVABLES_COMPLETE.equals(financialModel.get收款状态())){
                return new ResultData("false","收款未完成，不能登记整车发票!");
            } else {
                // 发票登记完毕后，不可以开整车票
                  if (FinanceConstant.INVOICE_COMPLETE.equals(financialModel.get开票状态())) {
                      return new ResultData("false","发票登记完毕，不能开整车票！");
                  }

            }

            if (!"开票O".equals(orderModel.get订单状态())){
                return new ResultData("false","销售顾问没有提交开票申请，不能登记整车发票!");
            }
        }

        // 3：发票金额 > 订单总价，不可以进行发票操作
        BigDecimal orderTotalAmount = this.financeReceivablesRepository.getOrderTotalPrice(quoteModel.get报价编号().toString());
        BigDecimal actualInvoiceMoney = financialModel.get开票金额().add(financialModel.get退票金额()).add(new BigDecimal(params.invoiceMoney));
        if (actualInvoiceMoney.compareTo(orderTotalAmount) > 0) {
            logger.warn("params={}， financialModel.get开票金额()={}, financialModel.get退票金额()={}, params.invoiceMoney={}, financialModel.get订单总价()={}", JsonObjectUtils.createJsonString(params), financialModel.get开票金额(), financialModel.get退票金额(), params.invoiceMoney, orderTotalAmount);

            result.setMessage("发票总金额不可以大于订单总价，发票登记失败！");
            result.setResult("false");
            return result;
        }
        // 4：如果已经开过整车票，则不可以再次开整车票了
        if ("item_allCar".equalsIgnoreCase(invoiceItemDic.get字典值())) {
            List<销售财务账目表Model> financeDetailModels = financialDetailRepository.selectByOrderNumAndItemTypeAndIsRed(params.initNum,FinanceConstant.FAPIAO,"0");
            if (null != financeDetailModels && !financeDetailModels.isEmpty()) {
                result.setMessage("已经开过整车票，不可以再开整车票了！");
                result.setResult("false");
                return result;
            }
        }
        Timestamp time = new Timestamp(System.currentTimeMillis());  // 当前时间
        BigDecimal money = new BigDecimal(params.invoiceMoney).setScale(2,BigDecimal.ROUND_HALF_UP); // 金额
        // 更新财务金额
        financialModel.set开票金额(financialModel.get开票金额().add(money));
        financialModel.set修改时间(time);
        financialModel.set修改用户(params.user);
        financialRepository.save(financialModel);

        // 插入账目明细
        销售财务账目表Model financialDetailModel = new 销售财务账目表Model();
        financialDetailModel.set财务编号(financialModel.get财务编号());
        financialDetailModel.set订单编号(params.initNum);
        financialDetailModel.set账目日期(new Date(DateFormatUtils.getFormatDate(params.invoiceDate, TIME_FORMAT_STR_YYYY_MM_DD).getTime()));
        financialDetailModel.set账目类型(FinanceConstant.FAPIAO);
        financialDetailModel.set发票项目(params.invoiceItem);
        financialDetailModel.set发票类型(params.invoiceType);
        financialDetailModel.set账目单号(generateOperationNumber(FinanceConstant.F));
        financialDetailModel.set账目金额(money);
        financialDetailModel.set交易凭证号(params.invoiceNumber);
        financialDetailModel.set是否红冲("0");
        financialDetailModel.set备注(params.remarks);
        financialDetailModel.set创建用户(params.user);
        financialDetailModel.set创建时间(time);
        financialDetailModel.set修改时间(time);
        financialDetailModel.set修改用户(params.user);
        financialDetailModel.set删除状态("0");
        financialDetailModel.set发票抬头(params.invoiceRise);
        financialDetailModel.set纳税人识别号(params.invoiceTaxNumber);
        financialDetailModel.set客户地址(params.address);
        financialDetailModel.set客户电话(params.phone);
        financialDetailModel.set客户开户行(params.bank);
        financialDetailModel.set客户账号(params.bankAccount);
        financialDetailModel.set操作日期(time);
        financialDetailRepository.save(financialDetailModel);
        return result;
    }

    @Override
    public PageData getFinanceReceivablesList(FinanceReceivablesBody.NewCarReceivablesListBody body) {
        return financeReceivablesRepository.getFinanceReceivablesList(body);
    }

    @Override
    public PageData getQuotaMoney( String quotedNum) {
        PageData page = new PageData();
        List list = financeReceivablesRepository.getQuotaMoney(quotedNum);
        page.setData(list);
        page.setTotal(list.size());
        return page;
    }


    @Override
    public ResultData getFinanceReceivablesInfo(FinanceReceivablesBody.NewCarReceivablesInfoBody body) {
        //操作模块
        List<Map> optList = financeReceivablesRepository.getReceivablesInfoByOperation(body.orderNumber);
        //款项模块
        List<Map> moneyList = financeReceivablesRepository.getReceivablesInfoByMoney(body.orderNumber);
        //订单模块
        List<Map> orderList = financeReceivablesRepository.getReceivablesInfoByOrder(body.orderNumber);
        //车辆模块
        List<Map> carList = financeReceivablesRepository.getReceivablesInfoByCar(body.vin);
        //编号模块
        List<Map> noList = financeReceivablesRepository.getReceivablesInfoNo(body.orderNumber);
        return  buildReceivablesInfo(optList,moneyList,orderList,carList,noList,body.orderNumber);
    }

    @Override
    public ResultData getFinanceReceivablesMoneyInfo(FinanceReceivablesBody.NewCarReceivablesInfoBody body) {
        //款项模块
        List<Map> moneyList = financeReceivablesRepository.getReceivablesInfoByMoney(body.orderNumber);
        return new ResultData("true",null,new PageData(getMoneyInfo(moneyList),1));
    }

    @Override
    public ResultData finishMoney(FinanceReceivablesBody.NewCarReceivablesInfoBody body) {
        销售财务表Model model = financialRepository.findByOrderNumber(body.orderNumber);
        if (null == model) {
            return new ResultData("false","完款操作失败，请先收款！");
        }
        // 检查是否可以点击完款操作
            // 已经是完款，不可以点击
        if (!StringUtils.isNullOrBlank(model.get收款状态()) && FinanceConstant.RECEIVABLES_COMPLETE.equals(model.get收款状态())) {
            return new ResultData("false","完款操作已完成，请勿重复操作！");
        }
            // 实收金额 <= 0,不可以点击完款
        BigDecimal actualReceivablesMoney = model.get收款金额().add(model.get红冲收款金额()).subtract(model.get退款金额().add(model.get红冲退款金额()));
        if (!(actualReceivablesMoney.compareTo(BigDecimal.ZERO) > 0)) {
            return new ResultData("false","当前订单的实际收款金额小于0，不可以点击完款操作！");
        }
        // 更改收款状态为“收款完成”
        model.set收款状态(FinanceConstant.RECEIVABLES_COMPLETE);
        model.set修改时间(new Timestamp(System.currentTimeMillis()));
        financialRepository.save(model);
        return new ResultData("true","订单号" + body.orderNumber + "确认完款,锁定相关财务操作！");
    }

    @Override
    public ResultData finishInvoice(FinanceReceivablesBody.NewCarReceivablesInfoBody body) throws Exception {
        销售财务表Model model = financialRepository.findByOrderNumber(body.orderNumber);
        if (null == model) {
            return new ResultData("false","发票登记操作失败，请先收款！");
        }
        // 先完款才能完毕
        if (!FinanceConstant.RECEIVABLES_COMPLETE.equals(model.get收款状态())) {
            return new ResultData("false","请先完款！");
        }
        // 开票已经完成，不可以再次点击
        if (FinanceConstant.INVOICE_COMPLETE.equals(model.get开票状态())) {
            return new ResultData("false","开票已经完成，请勿重复操作！");
        }
        // 检查是否开了有效的整车票
        List<销售财务账目表Model> financeDetailModels = financialDetailRepository.selectByOrderNumAndItemTypeAndIsRed(body.orderNumber,FinanceConstant.FAPIAO,"0");
        if (null == financeDetailModels || (financeDetailModels != null && financeDetailModels.isEmpty())) {
            return new ResultData("false","必须开了整车票才可以进行发票登记完毕操作！");
        }
        // 更改开票状态为“开票完成”
        model.set开票状态(FinanceConstant.INVOICE_COMPLETE);
        model.set修改时间(new Timestamp(System.currentTimeMillis()));
        financialRepository.save(model);

        // 获得最新的报价单数据
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(body.orderNumber);

        Lsh库存表Model stock = lsh库存表Repository.findOne(quotedModel.get库存编号());
        SetService.InvoicesState invoicesState = new SetService.InvoicesState();
        invoicesState.VIN = stock.get车架号();
        invoicesState.invoiceDate ="";
        invoicesState.remark = "";
        // 调用老财务的开票确认逻辑
        boolean flag = setService.updateInvoicesStateN(invoicesState,"");
        if (!flag) {
            logger.error("开票完毕失败，出现未知异常！");
            TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
            return new ResultData("false","发票登记完毕操作失败！");
        }
        return new ResultData("true","订单号" + body.orderNumber + "已确认发票登记完毕！");
    }

    /**
     * 构建详情
     * @param optList
     * @param moneyList
     * @param orderList
     * @param carList
     * @return
     */
    private ResultData buildReceivablesInfo(List<Map> optList,  List<Map> moneyList, List<Map> orderList,List<Map> carList,List<Map> noList,String orderNumber){
        NewCarReceivablesInfoVo vo = new NewCarReceivablesInfoVo();
        vo.setCarVo(getCarInfo(carList));
        // vo.setMoneyVoList(getMoneyInfo(moneyList));
        vo.setOrderVo(getOrderInfo(orderList));
        vo.setOperationVo(getOperationInfo(optList,moneyList,orderNumber));
        vo = initNo(vo,noList);
        List<NewCarReceivablesInfoVo> voList =  new ArrayList<NewCarReceivablesInfoVo>();
        voList.add(vo);
        return new ResultData("true","ok",new PageData(voList,1));
    }

    /**
     * 封装车辆
     * @param carList
     * @return
     */
    private ReceivablesInfoCarVo getCarInfo(List<Map> carList){
        ReceivablesInfoCarVo carVo = new ReceivablesInfoCarVo();
        for (Map map:carList) {
            carVo.setBrand(StringUtils.valueOf(map.get("brand")));
            carVo.setCarSeries(StringUtils.valueOf(map.get("series")));
            carVo.setCarModel(StringUtils.valueOf(map.get("model")));
            carVo.setCarStyle(StringUtils.valueOf(map.get("style")));
            carVo.setVin(StringUtils.valueOf(map.get("vin")));
            carVo.setLeaveCarState(StringUtils.valueOf(map.get("leaveCarState")));
            carVo.setExterior(StringUtils.valueOf(map.get("color")));
        }
        return carVo;
    }

    /**
     * 封装订单
     * @param orderList
     * @return
     */
    private ReceivablesInfoOrderVo getOrderInfo(List<Map> orderList){
        ReceivablesInfoOrderVo orderVo = new ReceivablesInfoOrderVo();
        for (Map map:orderList) {
            orderVo.setCardId(StringUtils.valueOf(map.get("cardId")));
            orderVo.setCompanyName(StringUtils.valueOf(map.get("company")));
            orderVo.setCustomerName(StringUtils.valueOf(map.get("customerName")));
            orderVo.setCustomerType(StringUtils.valueOf(map.get("customerType")));
            orderVo.setMobile(StringUtils.valueOf(map.get("mobile")));
            orderVo.setOrderNumber(StringUtils.valueOf(map.get("initQuoteNo")));
            orderVo.setOrderType(StringUtils.valueOf(map.get("orderType")));
            orderVo.setSaleType(StringUtils.valueOf(map.get("saleType")));
            orderVo.setScName(StringUtils.valueOf(map.get("scName")));
        }
        return orderVo;
    }

    /**
     * 封装操作
     * @param optList
     * @return
     */
    private ReceivablesInfoOperationVo getOperationInfo(List<Map> optList,List<Map> moneyList,String orderNumber){
        ReceivablesInfoOperationVo operationVo = new ReceivablesInfoOperationVo();
        for (Map map:optList) {
            operationVo.setSaleType(StringUtils.valueOf(map.get("saleType")));
            Double bill = Double.parseDouble(StringUtils.valueOf(map.get("bill")));
            Double redPush = getRedPushByType("挂账",orderNumber);
            operationVo.setBillAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(bill + redPush)));//挂账  + 红冲
            Double receivablesInit = Double.parseDouble(StringUtils.valueOf(map.get("receivables")));
            Double redPushReceivables = getRedPushByType("收款",orderNumber);
            operationVo.setCollectedAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(receivablesInit + redPushReceivables )));//收款 + 红冲
            Double invoice = Double.parseDouble(StringUtils.valueOf(map.get("invoice")));
            Double redPushInvoice = getRedPushByType("发票",orderNumber);
            operationVo.setInvoiceAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(invoice + redPushInvoice)));//开票  + 红冲
            Double refund = Double.parseDouble(StringUtils.valueOf(map.get("refund")));
            Double redPushRefund = getRedPushByType("退款",orderNumber);
            operationVo.setRefundAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(refund  + redPushRefund)));//退款  + 红冲
            operationVo.setOrderTotalAmount(moneyList.size() > 0 ?StringUtils.valueOf(new DecimalFormat("0.00").format(moneyList.get(0).get("totalPrice"))):"0.00");
            //实收 = 收款 - 退款
            Double receivables = Double.parseDouble(operationVo.getCollectedAmount()) - Double.parseDouble(operationVo.getRefundAmount());
            operationVo.setRealCollectedAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(receivables)));
            //应付 = 总计 - 实收 - 挂账
            Double payAmount = Double.parseDouble(operationVo.getOrderTotalAmount()) - Double.parseDouble(operationVo.getRealCollectedAmount()) -
                    Double.parseDouble(operationVo.getBillAmount());
            operationVo.setPayAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(payAmount)));
            Double writeOf = Double.parseDouble(StringUtils.valueOf(map.get("writeOf")));
            Double redPusnWriteOf = getRedPushByType("核销",orderNumber);  // 红冲核销
            // 挂销差额 = 挂账 - 核销
            operationVo.setBillWriteOfAmount(StringUtils.valueOf(new DecimalFormat("0.00").format(bill + redPush - (writeOf +redPusnWriteOf))));
        }
        return operationVo;
    }

    /**
     * 封装款项
     * @param moneyList
     * @return
     */
    private List<ReceivablesInfoMoneyVo> getMoneyInfo(List<Map> moneyList){
        List<ReceivablesInfoMoneyVo> list =  new ArrayList<ReceivablesInfoMoneyVo>();
        for (Map map:moneyList) {
            // 个数一定要是双数
            list.add(new ReceivablesInfoMoneyVo("车身价","carMsrp",StringUtils.valueOf(map.get("carMsrp")),"1"));
            list.add(new ReceivablesInfoMoneyVo("购置税","purchaseTax",StringUtils.valueOf(map.get("purchaseTax")),"2"));
            list.add(new ReceivablesInfoMoneyVo("订金金额","depositPrice",StringUtils.valueOf(map.get("depositPrice")),"3"));
            list.add(new ReceivablesInfoMoneyVo("上牌费","onTheCardPrice",StringUtils.valueOf(map.get("onTheCardPrice")),"4"));
            list.add(new ReceivablesInfoMoneyVo("精品费","boutiquePrice",StringUtils.valueOf(map.get("boutiquePrice")),"5"));
            list.add(new ReceivablesInfoMoneyVo("销售服务费","otherServcePrice",StringUtils.valueOf(map.get("otherServcePrice")),"6"));
            list.add(new ReceivablesInfoMoneyVo("贷款服务费","loanServicePrice",StringUtils.valueOf(map.get("loanServicePrice")),"7"));
            list.add(new ReceivablesInfoMoneyVo("置换手续费","displaceServicePrice",StringUtils.valueOf(map.get("displaceServicePrice")),"8"));
            list.add(new ReceivablesInfoMoneyVo("置换估价值","displacePrice",StringUtils.valueOf(map.get("displacePrice")),"9"));
            list.add(new ReceivablesInfoMoneyVo("授信挂账额度","creditAmount",StringUtils.valueOf(map.get("creditAmount")),"10"));
            list.add(new ReceivablesInfoMoneyVo("保险费(交强险+商业险)","insuranceTotal",StringUtils.valueOf(map.get("insuranceTotal")),"11"));
            list.add(new ReceivablesInfoMoneyVo("交强险","compulsoryInsurance",StringUtils.valueOf(map.get("compulsoryInsurance")),"12"));
            list.add(new ReceivablesInfoMoneyVo("商业险","commercialInsurance",StringUtils.valueOf(map.get("commercialInsurance")),"13"));
            list.add(new ReceivablesInfoMoneyVo("车船税","vehicleAndVesselTax",StringUtils.valueOf(map.get("vehicleAndVesselTax")),"14"));
            list.add(new ReceivablesInfoMoneyVo("厂家延保","vender",StringUtils.valueOf(map.get("vender")),"15"));
            list.add(new ReceivablesInfoMoneyVo("第三方延保","thirdExtended",StringUtils.valueOf(map.get("thirdExtended")),"16"));
            list.add(new ReceivablesInfoMoneyVo("本店延保","shop",StringUtils.valueOf(map.get("shop")),"17"));
            list.add(new ReceivablesInfoMoneyVo("预收款","prePayment",StringUtils.valueOf(map.get("prePayment")),"18"));
            list.add(new ReceivablesInfoMoneyVo("其他一","otherOne",StringUtils.valueOf(map.get("otherOne")),"19"));
            list.add(new ReceivablesInfoMoneyVo("其他二","otherTwo",StringUtils.valueOf(map.get("otherTwo")),"20"));
            list.add(new ReceivablesInfoMoneyVo("其他三","otherThree",StringUtils.valueOf(map.get("otherThree")),"21"));
            list.add(new ReceivablesInfoMoneyVo("其他四","otherFour",StringUtils.valueOf(map.get("otherFour")),"22"));
            list.add(new ReceivablesInfoMoneyVo("其他五","otherFive",StringUtils.valueOf(map.get("otherFive")),"23"));
            list.add(new ReceivablesInfoMoneyVo("","","","24"));   // 为了是双数，加上一个空的
        }
        return list;
    }

    /**
     * 初始化编号
     * @param vo
     * @param onList
     * @return
     */
    private NewCarReceivablesInfoVo initNo(NewCarReceivablesInfoVo vo,List<Map> onList){
        for (Map map:onList) {
            vo.setQuoteNo(Integer.parseInt(StringUtils.valueOf(map.get("quoteNo"))));
            vo.setInitQuoteNo(StringUtils.valueOf(map.get("initQuoteNo")));
            vo.setFinanceNo(StringUtils.isNullOrBlank(map.get("financeNo"))?null:Integer.parseInt(StringUtils.valueOf(map.get("financeNo"))));
            vo.setFinanceState(StringUtils.isNotNullOrBlank(map.get("financeState"))?null:StringUtils.valueOf(map.get("financeState")));
        }
        return vo;
    }


    /**
     * 获取订单编号对应账目分类的红冲总额
     * @param typeName
     * @param initQuoteNo
     * @return
     */
    public Double getRedPushByType(String typeName,String initQuoteNo){
        List<Map> list = financeReceivablesRepository.getIdListByAmountType(typeName,initQuoteNo);
        if (null == list || list.isEmpty()) {
            return new Double(0);
        }
        List<String> idList = new ArrayList<String>();//当前账目分类下相同类型的账目编号
        for(Map map:list){
            idList.add(StringUtils.isNullOrBlank(map.get("账目编号"))?null:StringUtils.valueOf(map.get("账目编号")));
        }
        //查询idList总红冲
        List<Map> reList =  financeReceivablesRepository.getRedPushById(idList);
        Double redPush = StringUtils.isNullOrBlank(reList.get(0).get("redPushTotal"))?0.00:Double.parseDouble(StringUtils.valueOf(reList.get(0).get("redPushTotal")));
        return redPush;
    }

    @Override
    public ResultData changeSaleType(SaleTypeRequest params) {
        报价单表Model quotedModel = 报价单表Repository.findOne(Integer.valueOf(params.quotedNum));
        报价单表Model lastModel = 报价单表Repository.findTheLastForFinance(quotedModel.get初始报价单号());
        报价订单表Model quotedOrderModel = 报价订单表Repository.findOne(lastModel.get订单编号());
        if (null == quotedOrderModel) {
            return new ResultData("false","变更失败，不存在订单信息！");
        }
        quotedOrderModel.set销售类型(params.saleType);
        报价订单表Repository.save(quotedOrderModel);
        return new ResultData("true","");
    }

    @Override
    @Transactional(readOnly = true)
    public ResultData getOrderFinanceStatus(String orderNumber) {
        销售财务表Model financeModel = financialRepository.findByOrderNumber(orderNumber);
        if (null == financeModel) {
            financeModel = new 销售财务表Model();
        }

        if (null != financeModel.get收款状态() && "01".equals(financeModel.get收款状态())) {
            financeModel.set收款状态("完成");
        } else {
            financeModel.set收款状态("未完成");
        }
        if (null != financeModel.get开票状态() && "01".equals(financeModel.get开票状态())) {
            financeModel.set开票状态("完成");
        } else {
            financeModel.set开票状态("未完成");
        }

        List list = new ArrayList();
        list.add(financeModel);
        return new ResultData("true",null,new PageData(list,list.size()));
    }

    @Override
    @Transactional(readOnly = true)
    public ResultData getBoutiqueDetails(String initNum) {
        ResultData result = new ResultData();
        // 得到最新的报价单信息
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(initNum);
        if (null == quotedModel) {
            logger.error("获取精品明细失败，无法获取最新的报价单信息");
            result.setResult("false");
            result.setMessage("获取精品明细失败，无法获取最新的报价单信息");
            return result;
        }
        List list = financeReceivablesRepository.getBoutiqueDetails(quotedModel.get报价编号().toString());
        result.setPageData(new PageData(list,list.size()));
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public ResultData getInsuranceDetails(String initNum) {
        ResultData result = new ResultData();
        // 得到最新的报价单信息
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(initNum);
        if (null == quotedModel) {
            logger.error("获取保险明细失败，无法获取最新的报价单信息");
            result.setResult("false");
            result.setMessage("获取保险明细失败，无法获取最新的报价单信息");
            return result;
        }
        List list = financeReceivablesRepository.getInsuranceDetails(quotedModel.get报价编号().toString());
        result.setPageData(new PageData(list,list.size()));
        return result;
    }

    @Override
    public ResultData getInsuranceInfo(String initNum) {
        ResultData result = new ResultData();
        // 得到最新的报价单信息
        报价单表Model quotedModel = 报价单表Repository.findTheLastForFinance(initNum);
        if (null == quotedModel) {
            logger.error("获取保险信息失败，无法获取最新的报价单信息");
            result.setResult("false");
            result.setMessage("获取保险信息失败，无法获取最新的报价单信息");
            return result;
        }
        List list = financeReceivablesRepository.getInsuranceInfo(quotedModel.get报价编号().toString());
        result.setPageData(new PageData(list,list.size()));
        return result;
    }

    /**
     * 是否是退订审批通过状态
     * @param initNum
     * @return
     */
    private boolean isRetreatStatus(String initNum) {
        boolean flag = false;
        // 得到最新的审批记录
        PushApprovalWorkFlowModel approvalModel = pushApprovalWorkFlowRepository2.getTheLastOneByInitNum(initNum);
        if (null == approvalModel) {
            flag = false;
        }
        List<Integer> typeList = new ArrayList<>();
        typeList.add(ApprovalWorkFlowEnum.ORDER_RETREAT);
        typeList.add(ApprovalWorkFlowEnum.ORDER_INTENTION_RETREAT);
        List<String> statusList = new ArrayList<>();
        statusList.add("1"); // 审批通过
        statusList.add("3");  // 审批自动通过
        // 若是退订，则不可以收款
        if (typeList.contains(approvalModel.getType()) && statusList.contains(approvalModel.getApprovalStatus())) {
            flag = true;
        }
        return flag;
    }
}
